package com.hexacta.hrs.web.struts.actions;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Row;
import org.vectrics.employee.Employee;
import org.vectrics.recruiter.job.JobFunction;
import org.vectrics.user.Person;

import com.hexacta.hrs.domain.employee.history.CareerRole;
import com.hexacta.hrs.domain.helper.EmployeeHelper;
import com.hexacta.hrs.domain.staffing.Client;
import com.hexacta.hrs.domain.staffing.Project;
import com.hexacta.hrs.domain.staffing.assignment.AssignmentType;
import com.hexacta.hrs.service.staffing.ClientService;
import com.hexacta.hrs.service.staffing.ProjectService;
import com.hexacta.hrs.services.employee.EmployeeService;
import com.hexacta.hrs.services.person.PersonService;

public class RowData {

    private JobFunction assignedRole;

    private AssignmentType assignmentType;

    private Person person;

    private Project project;

    private Client client;

    private double assignmentPorcentage;

    private Calendar endDate;

    private Calendar startDate;

    private static Map<String, AssignmentType> types;

    // si el type que llega es interno entonces se pasa a true
    private static boolean internal = false;

    private static Client defaultInternal; // definirlos de clase para no

    // buscarlo cada vez que se lo
    // necesite.

    private static Client defaultExternal; // definirlos de clase para no

    // buscarlo cada vez que se lo
    // necesite.

    private static Employee defaultResponsible;// definirlos de clase para no

    // buscarlo cada vez que se lo
    // necesite.

    private static HashMap<String, Project> projects = new HashMap<String, Project>();

    private static HashMap<String, Client> clients = new HashMap<String, Client>();

    private ProjectService projectService;

    private PersonService personService;

    private ClientService clientService;

    private EmployeeService employeeService;

    public RowData(final ProjectService projectService, final PersonService personService,
            final ClientService clientService, final EmployeeService employeeService, final Row data) {
        setProjectService(projectService);
        this.personService = personService;
        this.clientService = clientService;
        this.employeeService = employeeService;

        if (types == null) {
            initializeMap();
        }
        if (defaultExternal == null || defaultInternal == null || defaultResponsible == null) {
            initializeDefaults();
        }

        person = setPerson(data); // usar el service de Employee para
                                  // encontrar el employee que matchee
                                  // con ese nombre y apellido
        assignmentType = setAssignmentType(data);
        client = setClient(data);
        project = setProject(data);
        assignmentPorcentage = setPercentage(data);
        startDate = setStartDate(data);
        endDate = setEndDate(data);
        assignedRole = setRole(data);

    }

    private Client setClient(final Row data) {

        String clientName = data.getCell(8).getStringCellValue();

        if (clients.containsKey(clientName))
            return clients.get(clientName);

        Client cl = new Client();
        cl.setName(clientName);
        cl.setInternal(internal);

        List<Client> realCl = (List<Client>) clientService.searchByCriteria(cl);

        if (realCl == null || realCl.isEmpty()) {
            cl.setEmployeeInCharge(defaultResponsible);
            cl.setLocation(defaultExternal.getLocation());
            clientService.save(cl);

            clients.put(clientName, cl);
            return cl;
        } else {
            clients.put(clientName, realCl.get(0));
            return realCl.get(0);
        }

    }

    private Project setProject(final Row row) {

        String projectName = row.getCell(7).getStringCellValue();

        if (projects.containsKey(projectName))
            return projects.get(projectName);

        project = new Project();
        project.setName(projectName);
        List<Project> lista = (List<Project>) projectService.searchByCriteria(project);

        if (lista.isEmpty()) {
            project.setEmployeeInCharge(defaultResponsible);

            project.setClient(client);

            projectService.save(project);
        } else {
            project = lista.get(0);
        }

        projects.put(projectName, project);

        return project;

    }

    private void initializeDefaults() {
        Client Hx = new Client();
        Hx.setName("Hexacta");
        Hx.setInternal(true);

        Client Def = new Client();
        Def.setName("Default");
        Def.setInternal(false);

        Person searchPerson = new Person();
        searchPerson.setFirstName("%Javier%");
        searchPerson.setLastName("%Lagar%");
        Person p = ((List<Person>) personService.matching(searchPerson)).get(0);

        defaultInternal = ((List<Client>) clientService.searchByCriteria(Hx)).get(0);
        defaultExternal = ((List<Client>) clientService.searchByCriteria(Def)).get(0);
        defaultResponsible = employeeService.searchByPerson(p);

    }

    private void initializeMap() {
        types = new HashMap<String, AssignmentType>();
        types.put("Interno", AssignmentType.Assigned);
        types.put("Vendido", AssignmentType.Assigned);
        types.put("Asignado s/ vender", AssignmentType.AddOnNotAvailable);
        types.put("Add-on", AssignmentType.AddOnAvailable);

    }

    private JobFunction setRole(final Row row) {

        Employee emp = employeeService.searchByPerson(person);

        if (emp == null)
            return null;

        List<CareerRole> roles = EmployeeHelper.findRolesBetweenDates(emp, getStartDate().getTime(), getEndDate()
                .getTime());
        if (roles.isEmpty())
            return null;
        else
            return roles.get(0).getCareerRole();

    }

    private AssignmentType setAssignmentType(final Row row) {
        String assignment = row.getCell(9).getStringCellValue();

        if (assignment.equals("Interno")) {
            internal = true;
        } else {
            internal = false;
        }

        return types.get(assignment);
    }

    private Person setPerson(final Row row) {
        // en el excel solo hay nombre y apellido, no segundo nombre. uso la
        // primer palabra del
        // campo de nombre para matchear por nombre.
        String nombre = row.getCell(2).getStringCellValue().split(" ")[0];
        String apellido = row.getCell(1).getStringCellValue();

        Person searchPerson = new Person();
        searchPerson.setFirstName(nombre);
        searchPerson.setLastName(apellido);
        List<Person> persons = (List<Person>) personService.matching(searchPerson);

        if (persons.size() != 1)
            return null;
        return persons.get(0);
    }

    private double setPercentage(final Row row) {
        // el excel me devuelve el numero con tds los decimales porque lo
        // calcula una formula
        double percentageNotRounded = row.getCell(10).getNumericCellValue() * 100;
        BigDecimal bd = new BigDecimal(percentageNotRounded);
        // lo transformo
        double percentage = bd.setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
        return percentage;
    }

    private Calendar setStartDate(final Row row) {
        String month = row.getCell(13).getStringCellValue();
        String year = row.getCell(14).getStringCellValue();
        Calendar date = Calendar.getInstance();

        date.set(Integer.parseInt(year), Integer.parseInt(month) - 1, 1, 0, 0, 0);
        return date;
    }

    private Calendar setEndDate(final Row row) {
        String month = row.getCell(13).getStringCellValue();
        String year = row.getCell(14).getStringCellValue();
        Calendar date = new GregorianCalendar();

        Integer currentMonth = date.get(Calendar.MONTH);
        Integer currentYear = date.get(Calendar.YEAR);

        if (Integer.parseInt(month) == currentMonth + 1 && Integer.parseInt(year) == currentYear) {
            date.set(2011, Calendar.DECEMBER, 31, 0, 0, 0);
        } else {
            date.set(Integer.parseInt(year), Integer.parseInt(month) - 1, 1, 0, 0, 0);
            date.set(Calendar.DAY_OF_MONTH, date.getActualMaximum(Calendar.DAY_OF_MONTH));
        }
        return date;
    }

    public JobFunction getAssignedRole() {
        return assignedRole;
    }

    public AssignmentType getAssignmentType() {
        return assignmentType;
    }

    public Person getPerson() {
        return person;
    }

    public Project getProject() {
        return project;
    }

    public double getAssignmentPorcentage() {
        return assignmentPorcentage;
    }

    public Calendar getEndDate() {
        return endDate;
    }

    public Calendar getStartDate() {
        return startDate;
    }

    public static Map<String, AssignmentType> getTypes() {
        return types;
    }

    public static boolean isInternal() {
        return internal;
    }

    /**
     * @return the pr
     */
    public ProjectService getProjectService() {
        return projectService;
    }

    /**
     * @param pr
     *            the pr to set
     */
    public void setProjectService(final ProjectService projectService) {
        this.projectService = projectService;
    }

    /**
     * @param tmpRD
     * @return
     */
    public boolean equalsNoDate(final RowData other) {

        if (assignedRole == null) {
            if (other.assignedRole != null)
                return false;
        } else if (!assignedRole.equals(other.getAssignedRole()) && !other.assignedRole.equals(assignedRole))
            return false;
        if (Double.doubleToLongBits(assignmentPorcentage) != Double.doubleToLongBits(other.assignmentPorcentage))
            return false;
        if (assignmentType != other.assignmentType)
            return false;
        if (person == null) {
            if (other.person != null)
                return false;
        } else if (!person.equals(other.person))
            return false;
        if (project == null) {
            if (other.project != null)
                return false;
        } else if (!project.getName().equals(other.project.getName()))
            return false;
        return true;
    }

    /**
     * @param endDate
     *            the endDate to set
     */
    public void setEndDate(final Calendar endDate) {
        this.endDate = endDate;
    }

}
